1 /*
2 * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.security.auth;
27
28 import java.io.*;
29 import java.lang.RuntimePermission;
30 import java.lang.reflect.*;
31 import java.net.MalformedURLException;
32 import java.net.URL;
33 import java.util.*;
34
35 import java.security.AccessController;
36 import java.security.CodeSource;
37 import java.security.KeyStore;
38 import java.security.KeyStoreException;
39 import java.security.Permission;
40 import java.security.Permissions;
41 import java.security.PermissionCollection;
42 import java.security.Principal;
43 import java.security.UnresolvedPermission;
44 import java.security.Security;
45 import java.security.cert.Certificate;
46 import java.security.cert.X509Certificate;
47
48 import javax.security.auth.Subject;
49 import javax.security.auth.PrivateCredentialPermission;
50
51 import sun.security.util.PropertyExpander;
52
53 /**
54 * This class represents a default implementation for
55 * <code>javax.security.auth.Policy</code>.
56 *
57 * <p> This object stores the policy for entire Java runtime,
58 * and is the amalgamation of multiple static policy
59 * configurations that resides in files.
60 * The algorithm for locating the policy file(s) and reading their
61 * information into this <code>Policy</code> object is:
62 *
63 * <ol>
64 * <li>
65 * Loop through the <code>java.security.Security</code> properties,
66 * <i>auth.policy.url.1</i>, <i>auth.policy.url.2</i>, ...,
67 * <i>auth.policy.url.X</i>". These properties are set
68 * in the Java security properties file, which is located in the file named
69 * <JAVA_HOME>/lib/security/java.security.
70 * <JAVA_HOME> refers to the value of the java.home system property,
71 * and specifies the directory where the JRE is installed.
72 * Each property value specifies a <code>URL</code> pointing to a
73 * policy file to be loaded. Read in and load each policy.
74 *
75 * <li>
76 * The <code>java.lang.System</code> property <i>java.security.auth.policy</i>
77 * may also be set to a <code>URL</code> pointing to another policy file
78 * (which is the case when a user uses the -D switch at runtime).
79 * If this property is defined, and its use is allowed by the
80 * security property file (the Security property,
81 * <i>policy.allowSystemProperty</i> is set to <i>true</i>),
82 * also load that policy.
83 *
84 * <li>
85 * If the <i>java.security.auth.policy</i> property is defined using
86 * "==" (rather than "="), then ignore all other specified
87 * policies and only load this policy.
88 * </ol>
89 *
90 * Each policy file consists of one or more grant entries, each of
91 * which consists of a number of permission entries.
92 *
93 * <pre>
94 * grant signedBy "<b>alias</b>", codeBase "<b>URL</b>",
95 * principal <b>principalClass</b> "<b>principalName</b>",
96 * principal <b>principalClass</b> "<b>principalName</b>",
97 * ... {
98 *
99 * permission <b>Type</b> "<b>name</b> "<b>action</b>",
100 * signedBy "<b>alias</b>";
101 * permission <b>Type</b> "<b>name</b> "<b>action</b>",
102 * signedBy "<b>alias</b>";
103 * ....
104 * };
105 * </pre>
106 *
107 * All non-bold items above must appear as is (although case
108 * doesn't matter and some are optional, as noted below).
109 * Italicized items represent variable values.
110 *
111 * <p> A grant entry must begin with the word <code>grant</code>.
112 * The <code>signedBy</code> and <code>codeBase</code>
113 * name/value pairs are optional.
114 * If they are not present, then any signer (including unsigned code)
115 * will match, and any codeBase will match. Note that the
116 * <code>principal</code> name/value pair is not optional.
117 * This <code>Policy</code> implementation only permits
118 * Principal-based grant entries. Note that the <i>principalClass</i>
119 * may be set to the wildcard value, *, which allows it to match
120 * any <code>Principal</code> class. In addition, the <i>principalName</i>
121 * may also be set to the wildcard value, *, allowing it to match
122 * any <code>Principal</code> name. When setting the <i>principalName</i>
123 * to the *, do not surround the * with quotes.
124 *
125 * <p> A permission entry must begin with the word <code>permission</code>.
126 * The word <code><i>Type</i></code> in the template above is
127 * a specific permission type, such as <code>java.io.FilePermission</code>
128 * or <code>java.lang.RuntimePermission</code>.
129 *
130 * <p> The "<i>action</i>" is required for
131 * many permission types, such as <code>java.io.FilePermission</code>
132 * (where it specifies what type of file access that is permitted).
133 * It is not required for categories such as
134 * <code>java.lang.RuntimePermission</code>
135 * where it is not necessary - you either have the
136 * permission specified by the <code>"<i>name</i>"</code>
137 * value following the type name or you don't.
138 *
139 * <p> The <code>signedBy</code> name/value pair for a permission entry
140 * is optional. If present, it indicates a signed permission. That is,
141 * the permission class itself must be signed by the given alias in
142 * order for it to be granted. For example,
143 * suppose you have the following grant entry:
144 *
145 * <pre>
146 * grant principal foo.com.Principal "Duke" {
147 * permission Foo "foobar", signedBy "FooSoft";
148 * }
149 * </pre>
150 *
151 * <p> Then this permission of type <i>Foo</i> is granted if the
152 * <code>Foo.class</code> permission has been signed by the
153 * "FooSoft" alias, or if <code>Foo.class</code> is a
154 * system class (i.e., is found on the CLASSPATH).
155 *
156 * <p> Items that appear in an entry must appear in the specified order
157 * (<code>permission</code>, <i>Type</i>, "<i>name</i>", and
158 * "<i>action</i>"). An entry is terminated with a semicolon.
159 *
160 * <p> Case is unimportant for the identifiers (<code>permission</code>,
161 * <code>signedBy</code>, <code>codeBase</code>, etc.) but is
162 * significant for the <i>Type</i>
163 * or for any string that is passed in as a value. <p>
164 *
165 * <p> An example of two entries in a policy configuration file is
166 * <pre>
167 * // if the code is comes from "foo.com" and is running as "Duke",
168 * // grant it read/write to all files in /tmp.
169 *
170 * grant codeBase "foo.com", principal foo.com.Principal "Duke" {
171 * permission java.io.FilePermission "/tmp/*", "read,write";
172 * };
173 *
174 * // grant any code running as "Duke" permission to read
175 * // the "java.vendor" Property.
176 *
177 * grant principal foo.com.Principal "Duke" {
178 * permission java.util.PropertyPermission "java.vendor";
179 * </pre>
180 *
181 * <p> This <code>Policy</code> implementation supports
182 * special handling for PrivateCredentialPermissions.
183 * If a grant entry is configured with a
184 * <code>PrivateCredentialPermission</code>,
185 * and the "Principal Class/Principal Name" for that
186 * <code>PrivateCredentialPermission</code> is "self",
187 * then the entry grants the specified <code>Subject</code> permission to
188 * access its own private Credential. For example,
189 * the following grants the <code>Subject</code> "Duke"
190 * access to its own a.b.Credential.
191 *
192 * <pre>
193 * grant principal foo.com.Principal "Duke" {
194 * permission javax.security.auth.PrivateCredentialPermission
195 * "a.b.Credential self",
196 * "read";
197 * };
198 * </pre>
199 *
200 * The following grants the <code>Subject</code> "Duke"
201 * access to all of its own private Credentials:
202 *
203 * <pre>
204 * grant principal foo.com.Principal "Duke" {
205 * permission javax.security.auth.PrivateCredentialPermission
206 * "* self",
207 * "read";
208 * };
209 * </pre>
210 *
211 * The following grants all Subjects authenticated as a
212 * <code>SolarisPrincipal</code> (regardless of their respective names)
213 * permission to access their own private Credentials:
214 *
215 * <pre>
216 * grant principal com.sun.security.auth.SolarisPrincipal * {
217 * permission javax.security.auth.PrivateCredentialPermission
218 * "* self",
219 * "read";
220 * };
221 * </pre>
222 *
223 * The following grants all Subjects permission to access their own
224 * private Credentials:
225 *
226 * <pre>
227 * grant principal * * {
228 * permission javax.security.auth.PrivateCredentialPermission
229 * "* self",
230 * "read";
231 * };
232 * </pre>
233
234 * @deprecated As of JDK 1.4, replaced by
235 * <code>sun.security.provider.PolicyFile</code>.
236 * This class is entirely deprecated.
237 *
238 * @see java.security.CodeSource
239 * @see java.security.Permissions
240 * @see java.security.ProtectionDomain
241 */
242 @Deprecated
243 public class PolicyFile extends javax.security.auth.Policy {
244
245 static final java.util.ResourceBundle rb =
246 java.security.AccessController.doPrivileged
247 (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
248 public java.util.ResourceBundle run() {
249 return (java.util.ResourceBundle.getBundle
250 ("sun.security.util.AuthResources"));
251 }
252 });
253 // needs to be package private
254
255 private static final sun.security.util.Debug debug =
256 sun.security.util.Debug.getInstance("policy", "\t[Auth Policy]");
257
258 private static final String AUTH_POLICY = "java.security.auth.policy";
259 private static final String SECURITY_MANAGER = "java.security.manager";
260 private static final String AUTH_POLICY_URL = "auth.policy.url.";
261
262 private Vector<PolicyEntry> policyEntries;
263 private Hashtable aliasMapping;
264
265 private boolean initialized = false;
266
267 private boolean expandProperties = true;
268 private boolean ignoreIdentityScope = true;
269
270 // for use with the reflection API
271
272 private static final Class[] PARAMS = { String.class, String.class};
273
274 /**
275 * Initializes the Policy object and reads the default policy
276 * configuration file(s) into the Policy object.
277 */
278 public PolicyFile() {
279 // initialize Policy if either the AUTH_POLICY or
280 // SECURITY_MANAGER properties are set
281 String prop = System.getProperty(AUTH_POLICY);
282
283 if (prop == null) {
284 prop = System.getProperty(SECURITY_MANAGER);
285 }
286 if (prop != null)
287 init();
288 }
289
290 private synchronized void init() {
291
292 if (initialized)
293 return;
294
295 policyEntries = new Vector<PolicyEntry>();
296 aliasMapping = new Hashtable(11);
297
298 initPolicyFile();
299 initialized = true;
300 }
301
302 /**
303 * Refreshes the policy object by re-reading all the policy files.
304 *
305 * <p>
306 *
307 * @exception SecurityException if the caller doesn't have permission
308 * to refresh the <code>Policy</code>.
309 */
310 public synchronized void refresh()
311 {
312
313 java.lang.SecurityManager sm = System.getSecurityManager();
314 if (sm != null) {
315 sm.checkPermission(new javax.security.auth.AuthPermission
316 ("refreshPolicy"));
317 }
318
319 // XXX
320 //
321 // 1) if code instantiates PolicyFile directly, then it will need
322 // all the permissions required for the PolicyFile initialization
323 // 2) if code calls Policy.getPolicy, then it simply needs
324 // AuthPermission(getPolicy), and the javax.security.auth.Policy
325 // implementation instantiates PolicyFile in a doPrivileged block
326 // 3) if after instantiating a Policy (either via #1 or #2),
327 // code calls refresh, it simply needs
328 // AuthPermission(refreshPolicy). then PolicyFile wraps
329 // the refresh in a doPrivileged block.
330 initialized = false;
331 java.security.AccessController.doPrivileged
332 (new java.security.PrivilegedAction<Void>() {
333 public Void run() {
334 init();
335 return null;
336 }
337 });
338 }
339
340 private KeyStore initKeyStore(URL policyUrl, String keyStoreName,
341 String keyStoreType) {
342 if (keyStoreName != null) {
343 try {
344 /*
345 * location of keystore is specified as absolute URL in policy
346 * file, or is relative to URL of policy file
347 */
348 URL keyStoreUrl = null;
349 try {
350 keyStoreUrl = new URL(keyStoreName);
351 // absolute URL
352 } catch (java.net.MalformedURLException e) {
353 // relative URL
354 keyStoreUrl = new URL(policyUrl, keyStoreName);
355 }
356
357 if (debug != null) {
358 debug.println("reading keystore"+keyStoreUrl);
359 }
360
361 InputStream inStream =
362 new BufferedInputStream(getInputStream(keyStoreUrl));
363
364 KeyStore ks;
365 if (keyStoreType != null)
366 ks = KeyStore.getInstance(keyStoreType);
367 else
368 ks = KeyStore.getInstance(KeyStore.getDefaultType());
369 ks.load(inStream, null);
370 inStream.close();
371 return ks;
372 } catch (Exception e) {
373 // ignore, treat it like we have no keystore
374 if (debug != null) {
375 e.printStackTrace();
376 }
377 return null;
378 }
379 }
380 return null;
381 }
382
383 private void initPolicyFile() {
384
385 String prop = Security.getProperty("policy.expandProperties");
386
387 if (prop != null) expandProperties = prop.equalsIgnoreCase("true");
388
389 String iscp = Security.getProperty("policy.ignoreIdentityScope");
390
391 if (iscp != null) ignoreIdentityScope = iscp.equalsIgnoreCase("true");
392
393 String allowSys = Security.getProperty("policy.allowSystemProperty");
394
395 if ((allowSys!=null) && allowSys.equalsIgnoreCase("true")) {
396
397 String extra_policy = System.getProperty(AUTH_POLICY);
398 if (extra_policy != null) {
399 boolean overrideAll = false;
400 if (extra_policy.startsWith("=")) {
401 overrideAll = true;
402 extra_policy = extra_policy.substring(1);
403 }
404 try {
405 extra_policy = PropertyExpander.expand(extra_policy);
406 URL policyURL;;
407 File policyFile = new File(extra_policy);
408 if (policyFile.exists()) {
409 policyURL =
410 new URL("file:" + policyFile.getCanonicalPath());
411 } else {
412 policyURL = new URL(extra_policy);
413 }
414 if (debug != null)
415 debug.println("reading "+policyURL);
416 init(policyURL);
417 } catch (Exception e) {
418 // ignore.
419 if (debug != null) {
420 debug.println("caught exception: "+e);
421 }
422
423 }
424 if (overrideAll) {
425 if (debug != null) {
426 debug.println("overriding other policies!");
427 }
428 return;
429 }
430 }
431 }
432
433 int n = 1;
434 boolean loaded_one = false;
435 String policy_url;
436
437 while ((policy_url = Security.getProperty(AUTH_POLICY_URL+n)) != null) {
438 try {
439 policy_url = PropertyExpander.expand(policy_url).replace
440 (File.separatorChar, '/');
441 if (debug != null)
442 debug.println("reading "+policy_url);
443 init(new URL(policy_url));
444 loaded_one = true;
445 } catch (Exception e) {
446 if (debug != null) {
447 debug.println("error reading policy "+e);
448 e.printStackTrace();
449 }
450 // ignore that policy
451 }
452 n++;
453 }
454
455 if (loaded_one == false) {
456 // do not load a static policy
457 }
458 }
459
460 /**
461 * Checks public key. If it is marked as trusted in
462 * the identity database, add it to the policy
463 * with the AllPermission.
464 */
465 private boolean checkForTrustedIdentity(final Certificate cert) {
466 // XXX JAAS has no way to access the SUN package.
467 // we'll add this back in when JAAS goes into core.
468 return false;
469 }
470
471 /**
472 * Reads a policy configuration into the Policy object using a
473 * Reader object.
474 *
475 * @param policyFile the policy Reader object.
476 */
477 private void init(URL policy) {
478 PolicyParser pp = new PolicyParser(expandProperties);
479 try {
480 InputStreamReader isr
481 = new InputStreamReader(getInputStream(policy));
482 pp.read(isr);
483 isr.close();
484 KeyStore keyStore = initKeyStore(policy, pp.getKeyStoreUrl(),
485 pp.getKeyStoreType());
486 Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();
487 while (enum_.hasMoreElements()) {
488 PolicyParser.GrantEntry ge = enum_.nextElement();
489 addGrantEntry(ge, keyStore);
490 }
491 } catch (PolicyParser.ParsingException pe) {
492 System.err.println(AUTH_POLICY +
493 rb.getString(".error.parsing.") + policy);
494 System.err.println(AUTH_POLICY +
495 rb.getString("COLON") +
496 pe.getMessage());
497 if (debug != null)
498 pe.printStackTrace();
499
500 } catch (Exception e) {
501 if (debug != null) {
502 debug.println("error parsing "+policy);
503 debug.println(e.toString());
504 e.printStackTrace();
505 }
506 }
507 }
508
509 /*
510 * Fast path reading from file urls in order to avoid calling
511 * FileURLConnection.connect() which can be quite slow the first time
512 * it is called. We really should clean up FileURLConnection so that
513 * this is not a problem but in the meantime this fix helps reduce
514 * start up time noticeably for the new launcher. -- DAC
515 */
516 private InputStream getInputStream(URL url) throws IOException {
517 if ("file".equals(url.getProtocol())) {
518 String path = url.getFile().replace('/', File.separatorChar);
519 return new FileInputStream(path);
520 } else {
521 return url.openStream();
522 }
523 }
524
525 /**
526 * Given a PermissionEntry, create a codeSource.
527 *
528 * @return null if signedBy alias is not recognized
529 */
530 CodeSource getCodeSource(PolicyParser.GrantEntry ge, KeyStore keyStore)
531 throws java.net.MalformedURLException
532 {
533 Certificate[] certs = null;
534 if (ge.signedBy != null) {
535 certs = getCertificates(keyStore, ge.signedBy);
536 if (certs == null) {
537 // we don't have a key for this alias,
538 // just return
539 if (debug != null) {
540 debug.println(" no certs for alias " +
541 ge.signedBy + ", ignoring.");
542 }
543 return null;
544 }
545 }
546
547 URL location;
548
549 if (ge.codeBase != null)
550 location = new URL(ge.codeBase);
551 else
552 location = null;
553
554 if (ge.principals == null || ge.principals.size() == 0) {
555 return (canonicalizeCodebase
556 (new CodeSource(location, certs),
557 false));
558 } else {
559 return (canonicalizeCodebase
560 (new SubjectCodeSource(null, ge.principals, location, certs),
561 false));
562 }
563 }
564
565 /**
566 * Add one policy entry to the vector.
567 */
568 private void addGrantEntry(PolicyParser.GrantEntry ge,
569 KeyStore keyStore) {
570
571 if (debug != null) {
572 debug.println("Adding policy entry: ");
573 debug.println(" signedBy " + ge.signedBy);
574 debug.println(" codeBase " + ge.codeBase);
575 if (ge.principals != null && ge.principals.size() > 0) {
576 ListIterator<PolicyParser.PrincipalEntry> li =
577 ge.principals.listIterator();
578 while (li.hasNext()) {
579 PolicyParser.PrincipalEntry pppe = li.next();
580 debug.println(" " + pppe.principalClass +
581 " " + pppe.principalName);
582 }
583 }
584 debug.println();
585 }
586
587 try {
588 CodeSource codesource = getCodeSource(ge, keyStore);
589 // skip if signedBy alias was unknown...
590 if (codesource == null) return;
591
592 PolicyEntry entry = new PolicyEntry(codesource);
593 Enumeration<PolicyParser.PermissionEntry> enum_ =
594 ge.permissionElements();
595 while (enum_.hasMoreElements()) {
596 PolicyParser.PermissionEntry pe = enum_.nextElement();
597 try {
598 // XXX special case PrivateCredentialPermission-SELF
599 Permission perm;
600 if (pe.permission.equals
601 ("javax.security.auth.PrivateCredentialPermission") &&
602 pe.name.endsWith(" self")) {
603 perm = getInstance(pe.permission,
604 pe.name + " \"self\"",
605 pe.action);
606 } else {
607 perm = getInstance(pe.permission,
608 pe.name,
609 pe.action);
610 }
611 entry.add(perm);
612 if (debug != null) {
613 debug.println(" "+perm);
614 }
615 } catch (ClassNotFoundException cnfe) {
616 Certificate certs[];
617 if (pe.signedBy != null)
618 certs = getCertificates(keyStore, pe.signedBy);
619 else
620 certs = null;
621
622 // only add if we had no signer or we had a
623 // a signer and found the keys for it.
624 if (certs != null || pe.signedBy == null) {
625 Permission perm = new UnresolvedPermission(
626 pe.permission,
627 pe.name,
628 pe.action,
629 certs);
630 entry.add(perm);
631 if (debug != null) {
632 debug.println(" "+perm);
633 }
634 }
635 } catch (java.lang.reflect.InvocationTargetException ite) {
636 System.err.println
637 (AUTH_POLICY +
638 rb.getString(".error.adding.Permission.") +
639 pe.permission +
640 rb.getString("SPACE") +
641 ite.getTargetException());
642 } catch (Exception e) {
643 System.err.println
644 (AUTH_POLICY +
645 rb.getString(".error.adding.Permission.") +
646 pe.permission +
647 rb.getString("SPACE") +
648 e);
649 }
650 }
651 policyEntries.addElement(entry);
652 } catch (Exception e) {
653 System.err.println
654 (AUTH_POLICY +
655 rb.getString(".error.adding.Entry.") +
656 ge +
657 rb.getString("SPACE") +
658 e);
659 }
660
661 if (debug != null)
662 debug.println();
663 }
664
665 /**
666 * Returns a new Permission object of the given Type. The Permission is
667 * created by getting the
668 * Class object using the <code>Class.forName</code> method, and using
669 * the reflection API to invoke the (String name, String actions)
670 * constructor on the
671 * object.
672 *
673 * @param type the type of Permission being created.
674 * @param name the name of the Permission being created.
675 * @param actions the actions of the Permission being created.
676 *
677 * @exception ClassNotFoundException if the particular Permission
678 * class could not be found.
679 *
680 * @exception IllegalAccessException if the class or initializer is
681 * not accessible.
682 *
683 * @exception InstantiationException if getInstance tries to
684 * instantiate an abstract class or an interface, or if the
685 * instantiation fails for some other reason.
686 *
687 * @exception NoSuchMethodException if the (String, String) constructor
688 * is not found.
689 *
690 * @exception InvocationTargetException if the underlying Permission
691 * constructor throws an exception.
692 *
693 */
694
695 private static final Permission getInstance(String type,
696 String name,
697 String actions)
698 throws ClassNotFoundException,
699 InstantiationException,
700 IllegalAccessException,
701 NoSuchMethodException,
702 InvocationTargetException
703 {
704 //XXX we might want to keep a hash of created factories...
705 Class pc = Class.forName(type);
706 Constructor c = pc.getConstructor(PARAMS);
707 return (Permission) c.newInstance(new Object[] { name, actions });
708 }
709
710 /**
711 * Fetch all certs associated with this alias.
712 */
713 Certificate[] getCertificates(
714 KeyStore keyStore, String aliases) {
715
716 Vector<Certificate> vcerts = null;
717
718 StringTokenizer st = new StringTokenizer(aliases, ",");
719 int n = 0;
720
721 while (st.hasMoreTokens()) {
722 String alias = st.nextToken().trim();
723 n++;
724 Certificate cert = null;
725 //See if this alias's cert has already been cached
726 cert = (Certificate) aliasMapping.get(alias);
727 if (cert == null && keyStore != null) {
728
729 try {
730 cert = keyStore.getCertificate(alias);
731 } catch (KeyStoreException kse) {
732 // never happens, because keystore has already been loaded
733 // when we call this
734 }
735 if (cert != null) {
736 aliasMapping.put(alias, cert);
737 aliasMapping.put(cert, alias);
738 }
739 }
740
741 if (cert != null) {
742 if (vcerts == null)
743 vcerts = new Vector<Certificate>();
744 vcerts.addElement(cert);
745 }
746 }
747
748 // make sure n == vcerts.size, since we are doing a logical *and*
749 if (vcerts != null && n == vcerts.size()) {
750 Certificate[] certs = new Certificate[vcerts.size()];
751 vcerts.copyInto(certs);
752 return certs;
753 } else {
754 return null;
755 }
756 }
757
758 /**
759 * Enumerate all the entries in the global policy object.
760 * This method is used by policy admin tools. The tools
761 * should use the Enumeration methods on the returned object
762 * to fetch the elements sequentially.
763 */
764 private final synchronized Enumeration<PolicyEntry> elements(){
765 return policyEntries.elements();
766 }
767
768 /**
769 * Examines this <code>Policy</code> and returns the Permissions granted
770 * to the specified <code>Subject</code> and <code>CodeSource</code>.
771 *
772 * <p> Permissions for a particular <i>grant</i> entry are returned
773 * if the <code>CodeSource</code> constructed using the codebase and
774 * signedby values specified in the entry <code>implies</code>
775 * the <code>CodeSource</code> provided to this method, and if the
776 * <code>Subject</code> provided to this method contains all of the
777 * Principals specified in the entry.
778 *
779 * <p> The <code>Subject</code> provided to this method contains all
780 * of the Principals specified in the entry if, for each
781 * <code>Principal</code>, "P1", specified in the <i>grant</i> entry
782 * one of the following two conditions is met:
783 *
784 * <p>
785 * <ol>
786 * <li> the <code>Subject</code> has a
787 * <code>Principal</code>, "P2", where
788 * <code>P2.getClass().getName()</code> equals the
789 * P1's class name, and where
790 * <code>P2.getName()</code> equals the P1's name.
791 *
792 * <li> P1 implements
793 * <code>com.sun.security.auth.PrincipalComparator</code>,
794 * and <code>P1.implies</code> the provided <code>Subject</code>.
795 * </ol>
796 *
797 * <p> Note that this <code>Policy</code> implementation has
798 * special handling for PrivateCredentialPermissions.
799 * When this method encounters a <code>PrivateCredentialPermission</code>
800 * which specifies "self" as the <code>Principal</code> class and name,
801 * it does not add that <code>Permission</code> to the returned
802 * <code>PermissionCollection</code>. Instead, it builds
803 * a new <code>PrivateCredentialPermission</code>
804 * for each <code>Principal</code> associated with the provided
805 * <code>Subject</code>. Each new <code>PrivateCredentialPermission</code>
806 * contains the same Credential class as specified in the
807 * originally granted permission, as well as the Class and name
808 * for the respective <code>Principal</code>.
809 *
810 * <p>
811 *
812 * @param subject the Permissions granted to this <code>Subject</code>
813 * and the additionally provided <code>CodeSource</code>
814 * are returned. <p>
815 *
816 * @param codesource the Permissions granted to this <code>CodeSource</code>
817 * and the additionally provided <code>Subject</code>
818 * are returned.
819 *
820 * @return the Permissions granted to the provided <code>Subject</code>
821 * <code>CodeSource</code>.
822 */
823 public PermissionCollection getPermissions(final Subject subject,
824 final CodeSource codesource) {
825
826 // XXX when JAAS goes into the JDK core,
827 // we can remove this method and simply
828 // rely on the getPermissions variant that takes a codesource,
829 // which no one can use at this point in time.
830 // at that time, we can also make SubjectCodeSource a public
831 // class.
832
833 // XXX
834 //
835 // 1) if code instantiates PolicyFile directly, then it will need
836 // all the permissions required for the PolicyFile initialization
837 // 2) if code calls Policy.getPolicy, then it simply needs
838 // AuthPermission(getPolicy), and the javax.security.auth.Policy
839 // implementation instantiates PolicyFile in a doPrivileged block
840 // 3) if after instantiating a Policy (either via #1 or #2),
841 // code calls getPermissions, PolicyFile wraps the call
842 // in a doPrivileged block.
843 return java.security.AccessController.doPrivileged
844 (new java.security.PrivilegedAction<PermissionCollection>() {
845 public PermissionCollection run() {
846 SubjectCodeSource scs = new SubjectCodeSource
847 (subject,
848 null,
849 codesource == null ? null : codesource.getLocation(),
850 codesource == null ? null : codesource.getCertificates());
851 if (initialized)
852 return getPermissions(new Permissions(), scs);
853 else
854 return new PolicyPermissions(PolicyFile.this, scs);
855 }
856 });
857 }
858
859 /**
860 * Examines the global policy for the specified CodeSource, and
861 * creates a PermissionCollection object with
862 * the set of permissions for that principal's protection domain.
863 *
864 * @param CodeSource the codesource associated with the caller.
865 * This encapsulates the original location of the code (where the code
866 * came from) and the public key(s) of its signer.
867 *
868 * @return the set of permissions according to the policy.
869 */
870 PermissionCollection getPermissions(CodeSource codesource) {
871
872 if (initialized)
873 return getPermissions(new Permissions(), codesource);
874 else
875 return new PolicyPermissions(this, codesource);
876 }
877
878 /**
879 * Examines the global policy for the specified CodeSource, and
880 * creates a PermissionCollection object with
881 * the set of permissions for that principal's protection domain.
882 *
883 * @param permissions the permissions to populate
884 * @param codesource the codesource associated with the caller.
885 * This encapsulates the original location of the code (where the code
886 * came from) and the public key(s) of its signer.
887 *
888 * @return the set of permissions according to the policy.
889 */
890 Permissions getPermissions(final Permissions perms,
891 final CodeSource cs)
892 {
893 if (!initialized) {
894 init();
895 }
896
897 final CodeSource codesource[] = {null};
898
899 codesource[0] = canonicalizeCodebase(cs, true);
900
901 if (debug != null) {
902 debug.println("evaluate("+codesource[0]+")\n");
903 }
904
905 // needs to be in a begin/endPrivileged block because
906 // codesource.implies calls URL.equals which does an
907 // InetAddress lookup
908
909 for (int i = 0; i < policyEntries.size(); i++) {
910
911 PolicyEntry entry = policyEntries.elementAt(i);
912
913 if (debug != null) {
914 debug.println("PolicyFile CodeSource implies: " +
915 entry.codesource.toString() + "\n\n" +
916 "\t" + codesource[0].toString() + "\n\n");
917 }
918
919 if (entry.codesource.implies(codesource[0])) {
920 for (int j = 0; j < entry.permissions.size(); j++) {
921 Permission p = entry.permissions.elementAt(j);
922 if (debug != null) {
923 debug.println(" granting " + p);
924 }
925 if (!addSelfPermissions(p, entry.codesource,
926 codesource[0], perms)) {
927 // we could check for duplicates
928 // before adding new permissions,
929 // but the SubjectDomainCombiner
930 // already checks for duplicates later
931 perms.add(p);
932 }
933 }
934 }
935 }
936
937 // now see if any of the keys are trusted ids.
938
939 if (!ignoreIdentityScope) {
940 Certificate certs[] = codesource[0].getCertificates();
941 if (certs != null) {
942 for (int k=0; k < certs.length; k++) {
943 if ((aliasMapping.get(certs[k]) == null) &&
944 checkForTrustedIdentity(certs[k])) {
945 // checkForTrustedIdentity added it
946 // to the policy for us. next time
947 // around we'll find it. This time
948 // around we need to add it.
949 perms.add(new java.security.AllPermission());
950 }
951 }
952 }
953 }
954 return perms;
955 }
956
957 /**
958 * Returns true if 'Self' permissions were added to the provided
959 * 'perms', and false otherwise.
960 *
961 * <p>
962 *
963 * @param p check to see if this Permission is a "SELF"
964 * PrivateCredentialPermission. <p>
965 *
966 * @param entryCs the codesource for the Policy entry.
967 *
968 * @param accCs the codesource for from the current AccessControlContext.
969 *
970 * @param perms the PermissionCollection where the individual
971 * PrivateCredentialPermissions will be added.
972 */
973 private boolean addSelfPermissions(final Permission p,
974 CodeSource entryCs,
975 CodeSource accCs,
976 Permissions perms) {
977
978 if (!(p instanceof PrivateCredentialPermission))
979 return false;
980
981 if (!(entryCs instanceof SubjectCodeSource))
982 return false;
983
984
985 PrivateCredentialPermission pcp = (PrivateCredentialPermission)p;
986 SubjectCodeSource scs = (SubjectCodeSource)entryCs;
987
988 // see if it is a SELF permission
989 String[][] pPrincipals = pcp.getPrincipals();
990 if (pPrincipals.length <= 0 ||
991 !pPrincipals[0][0].equalsIgnoreCase("self") ||
992 !pPrincipals[0][1].equalsIgnoreCase("self")) {
993
994 // regular PrivateCredentialPermission
995 return false;
996 } else {
997
998 // granted a SELF permission - create a
999 // PrivateCredentialPermission for each
1000 // of the Policy entry's CodeSource Principals
1001
1002 if (scs.getPrincipals() == null) {
1003 // XXX SubjectCodeSource has no Subject???
1004 return true;
1005 }
1006
1007 ListIterator<PolicyParser.PrincipalEntry> pli =
1008 scs.getPrincipals().listIterator();
1009 while (pli.hasNext()) {
1010
1011 PolicyParser.PrincipalEntry principal = pli.next();
1012
1013 // XXX
1014 // if the Policy entry's Principal does not contain a
1015 // WILDCARD for the Principal name, then a
1016 // new PrivateCredentialPermission is created
1017 // for the Principal listed in the Policy entry.
1018 // if the Policy entry's Principal contains a WILDCARD
1019 // for the Principal name, then a new
1020 // PrivateCredentialPermission is created
1021 // for each Principal associated with the Subject
1022 // in the current ACC.
1023
1024 String[][] principalInfo = getPrincipalInfo
1025 (principal, accCs);
1026
1027 for (int i = 0; i < principalInfo.length; i++) {
1028
1029 // here's the new PrivateCredentialPermission
1030
1031 PrivateCredentialPermission newPcp =
1032 new PrivateCredentialPermission
1033 (pcp.getCredentialClass() +
1034 " " +
1035 principalInfo[i][0] +
1036 " " +
1037 "\"" + principalInfo[i][1] + "\"",
1038 "read");
1039
1040 if (debug != null) {
1041 debug.println("adding SELF permission: " +
1042 newPcp.toString());
1043 }
1044
1045 perms.add(newPcp);
1046 }
1047 }
1048 }
1049 return true;
1050 }
1051
1052 /**
1053 * return the principal class/name pair in the 2D array.
1054 * array[x][y]: x corresponds to the array length.
1055 * if (y == 0), it's the principal class.
1056 * if (y == 1), it's the principal name.
1057 */
1058 private String[][] getPrincipalInfo
1059 (PolicyParser.PrincipalEntry principal,
1060 final CodeSource accCs) {
1061
1062 // there are 3 possibilities:
1063 // 1) the entry's Principal class and name are not wildcarded
1064 // 2) the entry's Principal name is wildcarded only
1065 // 3) the entry's Principal class and name are wildcarded
1066
1067 if (!principal.principalClass.equals
1068 (PolicyParser.PrincipalEntry.WILDCARD_CLASS) &&
1069 !principal.principalName.equals
1070 (PolicyParser.PrincipalEntry.WILDCARD_NAME)) {
1071
1072 // build a PrivateCredentialPermission for the principal
1073 // from the Policy entry
1074 String[][] info = new String[1][2];
1075 info[0][0] = principal.principalClass;
1076 info[0][1] = principal.principalName;
1077 return info;
1078
1079 } else if (!principal.principalClass.equals
1080 (PolicyParser.PrincipalEntry.WILDCARD_CLASS) &&
1081 principal.principalName.equals
1082 (PolicyParser.PrincipalEntry.WILDCARD_NAME)) {
1083
1084 // build a PrivateCredentialPermission for all
1085 // the Subject's principals that are instances of principalClass
1086
1087 // the accCs is guaranteed to be a SubjectCodeSource
1088 // because the earlier CodeSource.implies succeeded
1089 SubjectCodeSource scs = (SubjectCodeSource)accCs;
1090
1091 Set<Principal> principalSet = null;
1092 try {
1093 Class pClass = Class.forName(principal.principalClass, false,
1094 ClassLoader.getSystemClassLoader());
1095 principalSet = scs.getSubject().getPrincipals(pClass);
1096 } catch (Exception e) {
1097 if (debug != null) {
1098 debug.println("problem finding Principal Class " +
1099 "when expanding SELF permission: " +
1100 e.toString());
1101 }
1102 }
1103
1104 if (principalSet == null) {
1105 // error
1106 return new String[0][0];
1107 }
1108
1109 String[][] info = new String[principalSet.size()][2];
1110 java.util.Iterator<Principal> pIterator = principalSet.iterator();
1111
1112 int i = 0;
1113 while (pIterator.hasNext()) {
1114 Principal p = pIterator.next();
1115 info[i][0] = p.getClass().getName();
1116 info[i][1] = p.getName();
1117 i++;
1118 }
1119 return info;
1120
1121 } else {
1122
1123 // build a PrivateCredentialPermission for every
1124 // one of the current Subject's principals
1125
1126 // the accCs is guaranteed to be a SubjectCodeSource
1127 // because the earlier CodeSource.implies succeeded
1128 SubjectCodeSource scs = (SubjectCodeSource)accCs;
1129 Set<Principal> principalSet = scs.getSubject().getPrincipals();
1130
1131 String[][] info = new String[principalSet.size()][2];
1132 java.util.Iterator<Principal> pIterator = principalSet.iterator();
1133
1134 int i = 0;
1135 while (pIterator.hasNext()) {
1136 Principal p = pIterator.next();
1137 info[i][0] = p.getClass().getName();
1138 info[i][1] = p.getName();
1139 i++;
1140 }
1141 return info;
1142 }
1143 }
1144
1145 /*
1146 * Returns the signer certificates from the list of certificates associated
1147 * with the given code source.
1148 *
1149 * The signer certificates are those certificates that were used to verify
1150 * signed code originating from the codesource location.
1151 *
1152 * This method assumes that in the given code source, each signer
1153 * certificate is followed by its supporting certificate chain
1154 * (which may be empty), and that the signer certificate and its
1155 * supporting certificate chain are ordered bottom-to-top (i.e., with the
1156 * signer certificate first and the (root) certificate authority last).
1157 */
1158 Certificate[] getSignerCertificates(CodeSource cs) {
1159 Certificate[] certs = null;
1160 if ((certs = cs.getCertificates()) == null)
1161 return null;
1162 for (int i=0; i<certs.length; i++) {
1163 if (!(certs[i] instanceof X509Certificate))
1164 return cs.getCertificates();
1165 }
1166
1167 // Do we have to do anything?
1168 int i = 0;
1169 int count = 0;
1170 while (i < certs.length) {
1171 count++;
1172 while (((i+1) < certs.length)
1173 && ((X509Certificate)certs[i]).getIssuerDN().equals(
1174 ((X509Certificate)certs[i+1]).getSubjectDN())) {
1175 i++;
1176 }
1177 i++;
1178 }
1179 if (count == certs.length)
1180 // Done
1181 return certs;
1182
1183 ArrayList<Certificate> userCertList = new ArrayList<>();
1184 i = 0;
1185 while (i < certs.length) {
1186 userCertList.add(certs[i]);
1187 while (((i+1) < certs.length)
1188 && ((X509Certificate)certs[i]).getIssuerDN().equals(
1189 ((X509Certificate)certs[i+1]).getSubjectDN())) {
1190 i++;
1191 }
1192 i++;
1193 }
1194 Certificate[] userCerts = new Certificate[userCertList.size()];
1195 userCertList.toArray(userCerts);
1196 return userCerts;
1197 }
1198
1199 private CodeSource canonicalizeCodebase(CodeSource cs,
1200 boolean extractSignerCerts) {
1201 CodeSource canonCs = cs;
1202 if (cs.getLocation() != null &&
1203 cs.getLocation().getProtocol().equalsIgnoreCase("file")) {
1204 try {
1205 String path = cs.getLocation().getFile().replace
1206 ('/',
1207 File.separatorChar);
1208 URL csUrl = null;
1209 if (path.endsWith("*")) {
1210 // remove trailing '*' because it causes canonicalization
1211 // to fail on win32
1212 path = path.substring(0, path.length()-1);
1213 boolean appendFileSep = false;
1214 if (path.endsWith(File.separator))
1215 appendFileSep = true;
1216 if (path.equals("")) {
1217 path = System.getProperty("user.dir");
1218 }
1219 File f = new File(path);
1220 path = f.getCanonicalPath();
1221 StringBuffer sb = new StringBuffer(path);
1222 // reappend '*' to canonicalized filename (note that
1223 // canonicalization may have removed trailing file
1224 // separator, so we have to check for that, too)
1225 if (!path.endsWith(File.separator) &&
1226 (appendFileSep || f.isDirectory()))
1227 sb.append(File.separatorChar);
1228 sb.append('*');
1229 path = sb.toString();
1230 } else {
1231 path = new File(path).getCanonicalPath();
1232 }
1233 csUrl = new File(path).toURL();
1234
1235 if (cs instanceof SubjectCodeSource) {
1236 SubjectCodeSource scs = (SubjectCodeSource)cs;
1237 if (extractSignerCerts) {
1238 canonCs = new SubjectCodeSource
1239 (scs.getSubject(),
1240 scs.getPrincipals(),
1241 csUrl,
1242 getSignerCertificates(scs));
1243 } else {
1244 canonCs = new SubjectCodeSource
1245 (scs.getSubject(),
1246 scs.getPrincipals(),
1247 csUrl,
1248 scs.getCertificates());
1249 }
1250 } else {
1251 if (extractSignerCerts) {
1252 canonCs = new CodeSource(csUrl,
1253 getSignerCertificates(cs));
1254 } else {
1255 canonCs = new CodeSource(csUrl,
1256 cs.getCertificates());
1257 }
1258 }
1259 } catch (IOException ioe) {
1260 // leave codesource as it is, unless we have to extract its
1261 // signer certificates
1262 if (extractSignerCerts) {
1263 if (!(cs instanceof SubjectCodeSource)) {
1264 canonCs = new CodeSource(cs.getLocation(),
1265 getSignerCertificates(cs));
1266 } else {
1267 SubjectCodeSource scs = (SubjectCodeSource)cs;
1268 canonCs = new SubjectCodeSource(scs.getSubject(),
1269 scs.getPrincipals(),
1270 scs.getLocation(),
1271 getSignerCertificates(scs));
1272 }
1273 }
1274 }
1275 } else {
1276 if (extractSignerCerts) {
1277 if (!(cs instanceof SubjectCodeSource)) {
1278 canonCs = new CodeSource(cs.getLocation(),
1279 getSignerCertificates(cs));
1280 } else {
1281 SubjectCodeSource scs = (SubjectCodeSource)cs;
1282 canonCs = new SubjectCodeSource(scs.getSubject(),
1283 scs.getPrincipals(),
1284 scs.getLocation(),
1285 getSignerCertificates(scs));
1286 }
1287 }
1288 }
1289 return canonCs;
1290 }
1291
1292 /**
1293 * Each entry in the policy configuration file is represented by a
1294 * PolicyEntry object. <p>
1295 *
1296 * A PolicyEntry is a (CodeSource,Permission) pair. The
1297 * CodeSource contains the (URL, PublicKey) that together identify
1298 * where the Java bytecodes come from and who (if anyone) signed
1299 * them. The URL could refer to localhost. The URL could also be
1300 * null, meaning that this policy entry is given to all comers, as
1301 * long as they match the signer field. The signer could be null,
1302 * meaning the code is not signed. <p>
1303 *
1304 * The Permission contains the (Type, Name, Action) triplet. <p>
1305 *
1306 * For now, the Policy object retrieves the public key from the
1307 * X.509 certificate on disk that corresponds to the signedBy
1308 * alias specified in the Policy config file. For reasons of
1309 * efficiency, the Policy object keeps a hashtable of certs already
1310 * read in. This could be replaced by a secure internal key
1311 * store.
1312 *
1313 * <p>
1314 * For example, the entry
1315 * <pre>
1316 * permission java.io.File "/tmp", "read,write",
1317 * signedBy "Duke";
1318 * </pre>
1319 * is represented internally
1320 * <pre>
1321 *
1322 * FilePermission f = new FilePermission("/tmp", "read,write");
1323 * PublicKey p = publickeys.get("Duke");
1324 * URL u = InetAddress.getLocalHost();
1325 * CodeBase c = new CodeBase( p, u );
1326 * pe = new PolicyEntry(f, c);
1327 * </pre>
1328 *
1329 * @author Marianne Mueller
1330 * @author Roland Schemers
1331 * @see java.security.CodeSource
1332 * @see java.security.Policy
1333 * @see java.security.Permissions
1334 * @see java.security.ProtectionDomain
1335 */
1336
1337 private static class PolicyEntry {
1338
1339 CodeSource codesource;
1340 Vector<Permission> permissions;
1341
1342 /**
1343 * Given a Permission and a CodeSource, create a policy entry.
1344 *
1345 * XXX Decide if/how to add validity fields and "purpose" fields to
1346 * XXX policy entries
1347 *
1348 * @param cs the CodeSource, which encapsulates the URL and the public
1349 * key
1350 * attributes from the policy config file. Validity checks are
1351 * performed on the public key before PolicyEntry is called.
1352 *
1353 */
1354 PolicyEntry(CodeSource cs)
1355 {
1356 this.codesource = cs;
1357 this.permissions = new Vector<Permission>();
1358 }
1359
1360 /**
1361 * add a Permission object to this entry.
1362 */
1363 void add(Permission p) {
1364 permissions.addElement(p);
1365 }
1366
1367 /**
1368 * Return the CodeSource for this policy entry
1369 */
1370 CodeSource getCodeSource() {
1371 return this.codesource;
1372 }
1373
1374 public String toString(){
1375 StringBuffer sb = new StringBuffer();
1376 sb.append(rb.getString("LPARAM"));
1377 sb.append(getCodeSource());
1378 sb.append("\n");
1379 for (int j = 0; j < permissions.size(); j++) {
1380 Permission p = permissions.elementAt(j);
1381 sb.append(rb.getString("SPACE"));
1382 sb.append(rb.getString("SPACE"));
1383 sb.append(p);
1384 sb.append(rb.getString("NEWLINE"));
1385 }
1386 sb.append(rb.getString("RPARAM"));
1387 sb.append(rb.getString("NEWLINE"));
1388 return sb.toString();
1389 }
1390
1391 }
1392 }
1393
1394 class PolicyPermissions extends PermissionCollection {
1395
1396 private static final long serialVersionUID = -1954188373270545523L;
1397
1398 private CodeSource codesource;
1399 private Permissions perms;
1400 private PolicyFile policy;
1401 private boolean notInit; // have we pulled in the policy permissions yet?
1402 private Vector<Permission> additionalPerms;
1403
1404 PolicyPermissions(PolicyFile policy,
1405 CodeSource codesource)
1406 {
1407 this.codesource = codesource;
1408 this.policy = policy;
1409 this.perms = null;
1410 this.notInit = true;
1411 this.additionalPerms = null;
1412 }
1413
1414 public void add(Permission permission) {
1415 if (isReadOnly())
1416 throw new SecurityException
1417 (PolicyFile.rb.getString
1418 ("attempt.to.add.a.Permission.to.a.readonly.PermissionCollection"));
1419
1420 if (perms == null) {
1421 if (additionalPerms == null)
1422 additionalPerms = new Vector<Permission>();
1423 additionalPerms.add(permission);
1424 } else {
1425 perms.add(permission);
1426 }
1427 }
1428
1429 private synchronized void init() {
1430 if (notInit) {
1431 if (perms == null)
1432 perms = new Permissions();
1433
1434 if (additionalPerms != null) {
1435 Enumeration<Permission> e = additionalPerms.elements();
1436 while (e.hasMoreElements()) {
1437 perms.add(e.nextElement());
1438 }
1439 additionalPerms = null;
1440 }
1441 policy.getPermissions(perms,codesource);
1442 notInit=false;
1443 }
1444 }
1445
1446 public boolean implies(Permission permission) {
1447 if (notInit)
1448 init();
1449 return perms.implies(permission);
1450 }
1451
1452 public Enumeration<Permission> elements() {
1453 if (notInit)
1454 init();
1455 return perms.elements();
1456 }
1457
1458 public String toString() {
1459 if (notInit)
1460 init();
1461 return perms.toString();
1462 }
1463 }